package com.bkhech.home.practice.socket.websocket.JavaWebsocket;

import org.java_websocket.WebSocket;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 服务器
 * A simple WebSocketServer implementation. Keeps track of a 'chatroom'.
 *
 * @author guowm
 * @date 2023/9/26
 */
public class ChatServer extends WebSocketServer {

    public ChatServer(int port) {
        super(new InetSocketAddress(port));
    }

    public ChatServer(InetSocketAddress address) {
        super(address);
    }

    public ChatServer(int port, Draft_6455 draft) {
        super(new InetSocketAddress(port), List.of(draft));
    }

    @Override
    public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
        //This method sends a message to the new client
        webSocket.send("Welcome to the server!");
        //This method sends a message to specified clients connected
        final ArrayList<WebSocket> excludeSelfWebSockets = getExcludeSelfWebSockets(webSocket);
        broadcast(clientHandshake.getResourceDescriptor() + " enter the room!", excludeSelfWebSockets);
        System.out.println(webSocket.getRemoteSocketAddress().getAddress().getHostAddress() + " " + clientHandshake.getResourceDescriptor() + " entered the room!");
    }

    private ArrayList<WebSocket> getExcludeSelfWebSockets(WebSocket webSocket) {
        final ArrayList<WebSocket> webSockets = new ArrayList<>(getConnections());
        webSockets.remove(webSocket);
        return webSockets;
    }

    @Override
    public void onMessage(WebSocket webSocket, String message) {
        if (!StringUtils.hasText(message)) {
            return;
        }
        if ("PING".equals(message)) {
            webSocket.send("PONG");
            return;
        }
        final ArrayList<WebSocket> excludeSelfWebSockets = getExcludeSelfWebSockets(webSocket);
        broadcast(webSocket.getResourceDescriptor() + " speak : " + message, excludeSelfWebSockets);
        System.out.println(webSocket.getResourceDescriptor() + ": " + message);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteBuffer message) {
        final ArrayList<WebSocket> excludeSelfWebSockets = getExcludeSelfWebSockets(webSocket);
        broadcast(message.array(), excludeSelfWebSockets);
        System.out.println(webSocket.getResourceDescriptor() + ": " + message);
    }

    @Override
    public void onClose(WebSocket webSocket, int code, String reason, boolean remote) {
        final ArrayList<WebSocket> excludeSelfWebSockets = getExcludeSelfWebSockets(webSocket);
        broadcast(webSocket + " has left the room!", excludeSelfWebSockets);
        System.out.println("onClose : "
                + " code = " + code
                + " reason = " + reason
                + " remote = " + remote);
    }

    @Override
    public void onError(WebSocket webSocket, Exception e) {
        e.printStackTrace();
        if (webSocket != null) {
            // some errors like port binding failed may not be assignable to a specific websocket
            System.out.println("onError : " + webSocket.getRemoteSocketAddress().getAddress().getHostAddress());
        }
    }

    @Override
    public void onStart() {
        System.out.println("Server started!");
        setConnectionLostTimeout(0);
        setMaxPendingConnections(100);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        int port = 8887;
        try {
            port = Integer.parseInt(args[0]);
        } catch (Exception e) {

        }
        ChatServer server = new ChatServer(port);
        server.start();
        System.out.println("ChatServer started on port: " + server.getPort());

        BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            final String in = sysin.readLine();
            server.broadcast(in);
            if (in.equals("exit")) {
                server.stop(1000);
                break;
            }
        }


    }
}
